#ifndef __server_H__
#define __server_H__
#define MAXCON 5
#define MAXSTR 1024
#define BIGSIZE 102400
#define STR_LEN 12
#define DIR_LEVEL 20
#define F_ret 0
#define S_ret 1
#define MD5_SIZE 16
#define MD5_STR_LEN 32
#define READ_DATA_SIZE 1024
#include <func.h>
#include <shadow.h>
#include <syslog.h>
#include "/usr/include/mysql/mysql.h"
typedef struct LOGIN_USR
{
    int sfd;
    int usr_id;
    int dir_id;
} Login_Usr;
typedef struct TRAIN
{
    int len;
    char buf[MAXSTR];
} Train;
typedef struct TASK
{
    Login_Usr usr;
    struct TASK *next;
    MYSQL *mysql_con;
} Task;
typedef struct Queue
{
    Task *front;
    Task *tail;
    int qsize;
    pthread_mutex_t mutex;
    pthread_cond_t cond;
} Task_Queue;
typedef struct POOL
{
    pthread_t *ptid;
    int pthread_num;
    Task_Queue tqueue;
    int exit_flag;
} Thread_Pool;
typedef struct USR
{
    int id;
    char username[20];
    char salt[13];
    char cryptpasswd[20];
    char pwd[1024];
} Usr;
typedef struct FAT_FILE
{
    int id;
    int parent_id;
    char filename[STR_LEN];
    int owner_id;
    char md5[33];
    int filesize;
    int type; // 0为文件，1为目录
} Fat_File;
typedef struct
{
    unsigned int count[2];
    unsigned int state[4];
    unsigned char buffer[64];
} MD5_CTX;
int exit_pipe[2];
void *thread_func(void *args);
void add_epoll(int efd, int sfd);
void add_queue(Task_Queue *task_queue, Login_Usr *login_usr, MYSQL *mysql_con);
void pop_queue(Task_Queue *task_queue);
void sig_func(int signum);
int init_socket(char *, char *);
int client_login(MYSQL *mysql_con, int sfd, int *usr_id);
void init_thread_pool(Thread_Pool *thread_pool, char *num);
void create_thread(Thread_Pool *thread_pool, int num);
void destroy_thread_pool(Thread_Pool *thread_pool);
MYSQL *init_mysql();
int add_mysql_usr(MYSQL *mysql_con, char *name, char *passwd, int *usr_id);
char *GenerateStr();
int select_mysql_usr(MYSQL *mysql_con, char *name, char *passwd, int *usr_id);
int usr_fat_init(MYSQL *mysql_con, int usr_id, char *name);
void del_mysql_usr(MYSQL *mysql_con, int usr_id);
void del_file(Task *task, char *filename);
int recvn(int sfd, void *p, int len);
int sendn(int sfd, void *str, int len);
int recv_file(int sfd, char *filename);
void send_file(int sfd, char *filename, off_t exist_size);
int select_file_sql(Task *task, char *filename, int *exist, char *md5_str);
void send_big_file(int fd, int sfd, off_t file_size, off_t exist_size);
void send_reg_file(int fd, int sfd, off_t file_size);
void recv_big_file(int fd, int sfd, off_t filesize);
void recv_reg_file(int fd, int sfd, off_t filesize);
int deal_cmd(Task *task);
void do_cd(Task *task, char *cmd);
void do_ls(Task *task);
void do_pwd(Task *task);
void do_puts(Task *task, char *cmd);
void do_gets(Task *task, char *cmd);
void do_rm(Task *task, char *cmd);
void do_mkdir(Task *task, char *cmd);
void select_dir_id(MYSQL *mysql_con, Login_Usr *login_usr);
MYSQL_RES *select_ls_cd_sql(Task *task);
MYSQL_RES *do_pwd_sql(MYSQL *mysql_con, int cur_id);
int add_file_sql(Task *task, Fat_File *newfile);
int compute_file_md5(char *file_path, char *md5_str, int filesize);
int selectfile_through_md5_sql(MYSQL *mysql_con, char *md5_str);
void modify_file_info_sql(Task *task, char *filename, char *md5_str, int filesize);
void insert_file_sql(MYSQL *mysql_con, Fat_File *fat_file);
int select_md5_num(Task *task, char *md5);
void modify_tmd5_md5(MYSQL *mysql_con, char *oldmd5, char *newmd5);
void copy_file(char *old, char *new);
void sub_md5_sql(MYSQL *mysql_con, char *md5);
void insert_md5_sql(Task *task, char *md5);
void del_md5_sql(MYSQL *mysql_con, char *md5);
void modify_md5_sql(Task *task, char *md5);
int select_md5_file(Task *task, char *filename, char *md5);

#define F(x, y, z) ((x & y) | (~x & z))
#define G(x, y, z) ((x & z) | (y & ~z))
#define H(x, y, z) (x ^ y ^ z)
#define I(x, y, z) (y ^ (x | ~z))
#define ROTATE_LEFT(x, n) ((x << n) | (x >> (32 - n)))

#define FF(a, b, c, d, x, s, ac)  \
    {                             \
        a += F(b, c, d) + x + ac; \
        a = ROTATE_LEFT(a, s);    \
        a += b;                   \
    }
#define GG(a, b, c, d, x, s, ac)  \
    {                             \
        a += G(b, c, d) + x + ac; \
        a = ROTATE_LEFT(a, s);    \
        a += b;                   \
    }
#define HH(a, b, c, d, x, s, ac)  \
    {                             \
        a += H(b, c, d) + x + ac; \
        a = ROTATE_LEFT(a, s);    \
        a += b;                   \
    }
#define II(a, b, c, d, x, s, ac)  \
    {                             \
        a += I(b, c, d) + x + ac; \
        a = ROTATE_LEFT(a, s);    \
        a += b;                   \
    }
void MD5Init(MD5_CTX *context);
void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int inputlen);
void MD5Final(MD5_CTX *context, unsigned char digest[16]);
void MD5Transform(unsigned int state[4], unsigned char block[64]);
void MD5Encode(unsigned char *output, unsigned int *input, unsigned int len);
void MD5Decode(unsigned int *output, unsigned char *input, unsigned int len);
#endif
